use super::Installer;
use anyhow::{bail, Result};
use once_cell::sync::Lazy;
use regex::Regex;
use std::fs::File;

pub fn fix_patches(installer: &Installer) -> Result<()> {
    fix_win_activate_scripts(installer)?;

    fix_matplotlibrc(installer)?;

    disable_labtensions(installer)?;

    disable_lsp_diagnostics(installer)?;

    fix_launcher_logo_svg(installer)?;

    disable_fetch_news(installer)?;

    toc_settings(installer)?;

    zh_locale_settings(installer)?;

    notebook_css_settings(installer)?;

    Ok(())
}

pub fn clean_cached_dir(installer: &Installer) -> Result<()> {
    let cached_dir = installer.cached_packages_dir.clone();

    if cached_dir.exists() {
        std::fs::remove_dir_all(cached_dir)?;
    }

    Ok(())
}

/// 将虚拟环境提示符改为(TGBA)
fn fix_win_activate_scripts(installer: &Installer) -> Result<()> {
    let mut script_path = installer.venv_dir.clone();
    script_path.extend(["Scripts", "activate.bat"]);

    let file = File::open(&script_path).unwrap();

    use std::io::{BufRead, BufReader};
    let reader = BufReader::new(file);

    let mut lines: Vec<String> = Vec::new();
    for line in reader.lines() {
        let Ok(line) = line else {
            bail!("从文件读取文本行错误")
        };

        if line.starts_with("@set \"VIRTUAL_ENV_PROMPT=\"") {
            lines.push(format!(
                "@set JUPYTER_CONFIG_DIR={}",
                installer.jupyter_config_dir().to_string_lossy()
            ));
            lines.push("@set \"VIRTUAL_ENV_PROMPT=TGBA\"".to_string());
        } else {
            lines.push(line);
        }
    }

    use std::io::Write;
    let mut file = File::create(&script_path)?;
    for line in lines {
        if let Err(err) = writeln!(file, "{}", line) {
            bail!("写入文件{}错误: {}", script_path.display(), err);
        }
    }

    Ok(())
}

static SANS_FONTS: [&str; 8] = [
    "Noto Sans CJK SC",
    "Microsoft YaHei",
    "SimHei",
    "DejaVu Sans",
    "Lucida Sans Unicode",
    "Arial",
    "Helvetica",
    "sans-serif",
];

static FONTFAMILY_REGEX: Lazy<Regex> = Lazy::new(|| {
    Regex::new(r#"#?(font\.family:.*)"#).unwrap() //
});

static SANSFAMILY_REGEX: Lazy<Regex> =
    Lazy::new(|| Regex::new(r#"#?(font\.sans-serif:).*"#).unwrap());

fn fix_matplotlibrc(installer: &Installer) -> Result<()> {
    let mut rcfile_path = installer.venv_dir.clone();
    rcfile_path.extend([
        "Lib",
        "site-packages",
        "matplotlib",
        "mpl-data",
        "matplotlibrc",
    ]);

    let rcfile = File::open(&rcfile_path).unwrap();
    use std::io::{BufRead, BufReader};

    let mut lines: Vec<String> = Vec::new();
    for line in BufReader::new(rcfile).lines() {
        let Ok(mut line) = line else {
            bail!("err: read a line")
        };

        match FONTFAMILY_REGEX.captures(&line) {
            Some(caps) => {
                line = format!("{}", &caps[1]);
                println!("{}", line);
            }
            _ => match SANSFAMILY_REGEX.captures(&line) {
                Some(caps) => {
                    line = format!("{} {}", &caps[1], SANS_FONTS.join(", "));
                    println!("{}", line);
                }
                _ => {}
            },
        }

        lines.push(line);
    }

    use std::io::Write;
    let mut file = File::create(&rcfile_path)?;
    for line in lines {
        if let Err(err) = writeln!(file, "{}", line) {
            bail!("写入文件{}错误: {}", rcfile_path.display(), err);
        }
    }

    Ok(())
}

fn disable_labtensions(installer: &Installer) -> Result<()> {
    let mut labconfig_path = installer.venv_dir.clone();
    labconfig_path.extend(["etc", "jupyter", "labconfig"]);
    if let Err(err) = std::fs::create_dir_all(&labconfig_path) {
        bail!(
            "创建jupyterlab配置目录{}失败: {}",
            labconfig_path.display(),
            err
        )
    }
    labconfig_path.push("page_config.json");

    let labconfig = r#"
{
    "disabledExtensions": {
        "@jupyterlab/cell-toolbar-extension": true,
        "@jupyterlab/debugger-extension": true
    }
}    
"#;

    use std::io::Write;
    let mut file = File::create(&labconfig_path)?;
    if let Err(err) = writeln!(file, "{}", labconfig) {
        bail!("写入文件{}错误: {}", labconfig_path.display(), err);
    }

    Ok(())
}

fn disable_lsp_diagnostics(installer: &Installer) -> Result<()> {
    // https://jupyterlab.readthedocs.io/en/stable/user/directories.html#overrides-json

    let mut settings_path = installer.venv_dir.clone();
    settings_path.extend(["share", "jupyter", "lab", "settings"]);
    if let Err(err) = std::fs::create_dir_all(&settings_path) {
        bail!(
            "创建jupyterlab配置目录{}失败: {}",
            settings_path.display(),
            err
        )
    }
    settings_path.push("overrides.json");

    let config = r#"
    {
        "@jupyter-lsp/jupyterlab-lsp:diagnostics": {
            "defaultSeverity": "Error",
            "disable": true
        }
    } 
"#;

    use std::io::Write;
    let mut file = File::create(&settings_path)?;
    if let Err(err) = writeln!(file, "{}", config) {
        bail!("写入文件{}错误: {}", settings_path.display(), err);
    }

    Ok(())
}

fn fix_launcher_logo_svg(installer: &Installer) -> Result<()> {
    let mut logo_svg_file = installer.venv_dir.clone();
    logo_svg_file.extend(["share", "jupyter", "kernels", "python3", "logo-svg.svg"]);

    if logo_svg_file.exists() {
        std::fs::remove_file(logo_svg_file)?;
        log::info!("删除logo-svg.svg，解决launcher无法正常显示Bug");
    }

    Ok(())
}

fn disable_fetch_news(installer: &Installer) -> Result<()> {
    let mut extension_dir = installer.jupyter_config_dir();
    extension_dir.extend(["lab", "user-settings", "@jupyterlab", "apputils-extension"]);
    if let Err(_err) = std::fs::create_dir_all(&extension_dir) {
        bail!("创建目录{}失败: {}", extension_dir.display(), _err)
    }

    let settings_file = extension_dir.join("notification.jupyterlab-settings");

    let Ok(mut file) = std::fs::File::create(&settings_file) else {
        bail!("无法创建配置文件: {}", settings_file.display())
    };

    use std::io::Write;
    file.write_all(
        r#"{
    "fetchNews": "false",
    "checkForUpdates": false,
    "doNotDisturbMode": false
}"#
        .as_bytes(),
    )?;
    file.flush()?;
    Ok(())
}

fn toc_settings(installer: &Installer) -> Result<()> {
    let mut extension_dir = installer.jupyter_config_dir();
    extension_dir.extend(["lab", "user-settings", "@jupyterlab", "toc-extension"]);
    if let Err(_err) = std::fs::create_dir_all(&extension_dir) {
        bail!("创建目录{}失败: {}", extension_dir.display(), _err)
    }

    let file = extension_dir.join("registry.jupyterlab-settings");
    let Ok(mut file) = std::fs::File::create(&file) else {
        bail!("无法创建配置文件: {}", file.display())
    };

    use std::io::Write;
    file.write_all(
        r#"{
    "maximalDepth": 5,
    "numberingH1": false,
    "numberHeaders": true,
    "includeOutput": true,
    "syncCollapseState": false,
    "baseNumbering": 1
}"#
        .as_bytes(),
    )?;
    file.flush()?;
    Ok(())
}

fn zh_locale_settings(installer: &Installer) -> Result<()> {
    let mut extension_dir = installer.jupyter_config_dir();
    extension_dir.extend([
        "lab",
        "user-settings",
        "@jupyterlab",
        "translation-extension",
    ]);
    if let Err(_err) = std::fs::create_dir_all(&extension_dir) {
        bail!("创建目录{}失败: {}", extension_dir.display(), _err)
    }

    let file = extension_dir.join("plugin.jupyterlab-settings");
    let Ok(mut file) = std::fs::File::create(&file) else {
        bail!("无法创建配置文件: {}", file.display())
    };

    use std::io::Write;
    file.write_all(
        r#"{
    "locale": "zh_CN"
}"#
        .as_bytes(),
    )?;
    file.flush()?;
    Ok(())
}

fn notebook_css_settings(installer: &Installer) -> Result<()> {
    let mut extension_dir = installer.jupyter_config_dir();
    extension_dir.extend(["custom"]);
    if let Err(_err) = std::fs::create_dir_all(&extension_dir) {
        bail!("创建目录{}失败: {}", extension_dir.display(), _err)
    }

    let file = extension_dir.join("custom.css");
    let Ok(mut file) = std::fs::File::create(&file) else {
        bail!("无法创建CSS文件: {}", file.display())
    };

    use std::io::Write;
    file.write_all(
        r#"
.jp-Notebook .jp-MarkdownOutput>h1 {
    font-size: 1.8rem;
    text-align: center;
    text-decoration: underline;
    text-decoration-style: double;
}

.jp-Notebook .jp-MarkdownOutput>h2 {
    font-size: 1.5rem;
    text-align: center;
    text-decoration: underline;
}

.jp-Notebook .jp-MarkdownOutput>h3 {
    font-size: 1.2rem;
    text-decoration: underline;
    text-decoration-style: double;
}

.jp-Notebook .jp-MarkdownOutput>h4 {
    font-size: 1rem;
    text-decoration: underline;
}


.jp-Notebook .jp-MarkdownOutput>h1,
.jp-Notebook .jp-MarkdownOutput>h2,
.jp-Notebook .jp-MarkdownOutput>h3,
.jp-Notebook .jp-MarkdownOutput>h4 {
    font-family: "Arial", "黑体";
    text-shadow: 1px 1px 2px #aaa;

    color: #752270;
    font-weight: 500;
    text-underline-offset: 5px;
    text-decoration-thickness: 1px;

}

.jp-Notebook .jp-MarkdownOutput>h1>a,
.jp-Notebook .jp-MarkdownOutput>h2>a,
.jp-Notebook .jp-MarkdownOutput>h3>a,
.jp-Notebook .jp-MarkdownOutput>h4>a {
    text-decoration: none;
    display: inline-block;
}

.jp-Notebook .jp-MarkdownOutput>h4 > .numbering-entry,
.jp-Notebook .jp-MarkdownOutput>h5 > .numbering-entry {
    display: none;
}

.jp-Notebook .jp-MarkdownOutput>h4::before {
    content: "▋";
}


.jp-Notebook .jp-MarkdownOutput>h5 {
    font-family: "Times New Roman", "宋体";
    text-shadow: 1px 1px 2px #aaa;
    color: #752270;
    font-size: 1rem;
    font-weight: bold;
}

/* 因JuyterLab的viewport动态加入和删除，无法直接使用序号 */
.jp-Notebook .jp-MarkdownOutput>h5:before {
    content: "➤";
    margin-right: 0.5em;
}


.jp-Notebook .jp-MarkdownOutput>p {
    font-family: "Times New Roman", "宋体";
    text-align: left;
    margin: 0 0 1em 0;
}

.jp-Notebook .jp-MarkdownOutput>p:last-child {
    margin-bottom: 0;
}
"#
        .as_bytes(),
    )?;
    file.flush()?;
    Ok(())
}
